ISRO SAC Forecast Viz#

Hide code cell content
import datetime


import astral
import cf_xarray  # noqa
import xarray as xr

import hvplot.xarray  # noqa
import holoviews as hv

import matplotlib.pyplot as plt

plt.rcParams["font.size"] = 13

hv.notebook_extension("bokeh")

time = datetime.datetime.now()
nice_time = time.strftime("%Y-%m-%dT%T")
print(f"Last updated: {time}")

%load_ext watermark
%watermark -iv
sys       : 3.11.3 | packaged by conda-forge | (main, Apr  6 2023, 08:57:19) [GCC 11.3.0]
hvplot    : 0.8.3
json      : 2.0.9
xarray    : 2022.12.0
matplotlib: 3.7.1
holoviews : 1.16.1
cf_xarray : 0.8.1
hv.opts.defaults(
    hv.opts.Curve(muted_alpha=0, fontscale=1.3, line_width=2, color=hv.Cycle("Dark2")),
    hv.opts.Area(color=hv.Cycle("Dark2"), muted_fill_alpha=0, muted_line_alpha=0),
    hv.opts.Layout(fontscale=1.3, sizing_mode="stretch_width", toolbar="left"),
    hv.opts.Overlay(
        active_tools=["box_zoom"],
        default_tools=["save", "pan", "box_zoom", "reset"],
        toolbar="left",
    ),
)

Read forecast data#

ds = astral.read_forecast_data()
ds
<xarray.Dataset>
Dimensions:   (xt_i: 560, yt_j: 400, xu_i: 560, yu_j: 400, zt_k: 50, lead: 21,
               init: 2)
Coordinates:
  * xt_i      (xt_i) float32 27.5 28.5 29.48 30.46 ... 138.5 139.5 140.5 141.5
  * yt_j      (yt_j) float32 -34.5 -33.5 -32.52 -31.54 ... 25.75 25.85 25.95
  * xu_i      (xu_i) float32 28.0 28.99 29.97 30.93 ... 139.0 140.0 141.0 142.0
  * yu_j      (yu_j) float32 -34.0 -33.01 -32.03 -31.07 ... 25.7 25.8 25.9 26.0
  * zt_k      (zt_k) float32 1.0 3.017 5.084 ... 4.175e+03 4.731e+03 5.32e+03
  * lead      (lead) timedelta64[ns] 0 days 00:00:00 ... 5 days 00:00:00
  * init      (init) datetime64[ns] 2023-06-02 2023-06-03
    time      (init, lead) datetime64[ns] 2023-06-02 ... 2023-06-08
Data variables:
    temp      (init, lead, zt_k, yt_j, xt_i) float32 dask.array<chunksize=(1, 21, 50, 400, 560), meta=np.ndarray>
    salinity  (init, lead, zt_k, yt_j, xt_i) float32 dask.array<chunksize=(1, 21, 50, 400, 560), meta=np.ndarray>
    u         (init, lead, zt_k, yu_j, xu_i) float32 dask.array<chunksize=(1, 21, 50, 400, 560), meta=np.ndarray>
    v         (init, lead, zt_k, yu_j, xu_i) float32 dask.array<chunksize=(1, 21, 50, 400, 560), meta=np.ndarray>
    hmxl      (init, lead, yt_j, xt_i) float32 dask.array<chunksize=(1, 21, 400, 560), meta=np.ndarray>
Attributes:
    CDI:             Climate Data Interface version 1.7.0 (http://mpimet.mpg....
    Conventions:     CF-1.4
    history:         Fri Jun 02 16:25:33 2023: cdo cat -settaxis,2023-06-02,0...
    filename:        time_mean.000047.06.02.dta.nc
    MPP_IO_VERSION:  $Id: mpp_io.F90,v 5.3 1999/12/03 16:59:31 vb Exp $
    title:           Time mean  {MOM 3.0}
    CDO:             Climate Data Operators version 1.7.0 (http://mpimet.mpg....

Subset to moorings#

moors = xr.concat(
    [
        ds.cf.sel(**loc, method="nearest")
        .assign_coords(moor=name)
        .cf.sel(Z=slice(500))  # .load()
        for name, loc in astral.LOCS.items()
    ],
    dim="moor",
)
moors.attrs["last_extracted"] = nice_time
moors
<xarray.Dataset>
Dimensions:   (moor: 3, zt_k: 33, lead: 21, init: 2)
Coordinates:
    xt_i      (moor) float32 67.45 68.95 68.65
    yt_j      (moor) float32 18.55 14.95 12.05
    xu_i      (moor) float32 67.4 69.0 68.6
    yu_j      (moor) float32 18.5 14.9 12.1
  * zt_k      (zt_k) float32 1.0 3.017 5.084 7.23 ... 316.1 363.7 423.7 496.1
  * lead      (lead) timedelta64[ns] 0 days 00:00:00 ... 5 days 00:00:00
  * init      (init) datetime64[ns] 2023-06-02 2023-06-03
    time      (init, lead) datetime64[ns] 2023-06-02 ... 2023-06-08
  * moor      (moor) <U4 'AD06' 'AD07' 'AD08'
Data variables:
    temp      (moor, init, lead, zt_k) float32 dask.array<chunksize=(1, 1, 21, 33), meta=np.ndarray>
    salinity  (moor, init, lead, zt_k) float32 dask.array<chunksize=(1, 1, 21, 33), meta=np.ndarray>
    u         (moor, init, lead, zt_k) float32 dask.array<chunksize=(1, 1, 21, 33), meta=np.ndarray>
    v         (moor, init, lead, zt_k) float32 dask.array<chunksize=(1, 1, 21, 33), meta=np.ndarray>
    hmxl      (moor, init, lead) float32 dask.array<chunksize=(1, 1, 21), meta=np.ndarray>
Attributes:
    CDI:             Climate Data Interface version 1.7.0 (http://mpimet.mpg....
    Conventions:     CF-1.4
    history:         Fri Jun 02 16:25:33 2023: cdo cat -settaxis,2023-06-02,0...
    filename:        time_mean.000047.06.02.dta.nc
    MPP_IO_VERSION:  $Id: mpp_io.F90,v 5.3 1999/12/03 16:59:31 vb Exp $
    title:           Time mean  {MOM 3.0}
    CDO:             Climate Data Operators version 1.7.0 (http://mpimet.mpg....
    last_extracted:  2023-06-05T09:25:54
moors.load().to_netcdf(
    f"isro-forecast-ad-moorings-{nice_time.replace(':', '.')}.nc", mode="w"
)

SST, SSS, HMXL timeseries#

surf = moors.cf.sel(Z=0, method="nearest").load()
astral.plot_surface_vars(moors.sel(moor="AD06"))
astral.plot_surface_vars(moors.sel(moor="AD07"))
astral.plot_surface_vars(moors.sel(moor="AD08"))

T, S forecast profiles#

T#

%autoreload

astral.plot_forecast_offset_lines(moors.temp)

S#

%autoreload

astral.plot_forecast_offset_lines(moors.salinity)

T, S, U, V maps#

subset = ds.cf.sel(
    X=slice(63, 78), Y=slice(4, 24), Z=slice(200), lead=slice(None, None, 4)
).load()
decimated = subset.cf.isel(
    init=-1, Y=slice(None, None, 4), X=slice(None, None, 4)
).load()

T#

Hide code cell source
%autoreload

astral.plot_facetgrid(subset.temp.cf.sel(Y=slice(20)), decimated)
<xarray.plot.facetgrid.FacetGrid at 0x2b32dd703690>
_images/31baa57a5f308768dfcf7599072adbfb5cf98b58ce547dd3f9de031885fd1c7e.png

S#

Hide code cell source
astral.plot_facetgrid(subset.salinity.cf.sel(Y=slice(20)), decimated)
<xarray.plot.facetgrid.FacetGrid at 0x2b32de73e8d0>
_images/9022ce32a069b8edfb7e90939fa74ec0f5ad5ba281c15c63fd564ac580c20633.png

mixed layer depth#

Hide code cell source
%autoreload

fg = astral.plot_facetgrid(subset.hmxl, decimated, cbar_location="bottom", pad=0.3)
fg.fig.set_size_inches((14, 6))
_images/00b36faf873399f0968ad9c4865c71b2109a73b4e3ad4528d5a760811ae2899a.png

Animations#

subset = ds.cf.sel(
    X=slice(63, 78),
    Y=slice(4, 24),
    Z=slice(200),
).load()
decimated = subset.cf.isel(
    init=-1, Y=slice(None, None, 4), X=slice(None, None, 4)
).load()
%autoreload
fg = {
    "temp": astral.plot_frame(subset.temp.isel(init=-1), decimated, cmap="coolwarm"),
    "salinity": astral.plot_frame(
        subset.salinity.isel(init=-1), decimated, cmap="plasma_r"
    ),
}
_images/bd48885e3dfdc97aa926c28eafec51d7a1d7c028a4e9ff11d9fd00182185419f.png _images/baf561fff8e8c214ee75084cb49d246199290c0e90777ea134bb3f344485fe36.png
import matplotlib.animation as animation
from functools import partial
import tqdm

for var in tqdm.tqdm(["temp", "salinity"]):
    ani = animation.FuncAnimation(
        fg[var].fig,
        partial(
            astral.update_frame_lead,
            varname=var,
            fg=fg[var],
            subset=subset,
            decimated=decimated,
        ),
        repeat=True,
        frames=subset.sizes["lead"] - 1,
        interval=50,
    )

    writer = animation.PillowWriter(fps=3, bitrate=1800)
    ani.save(f"{var}.gif", writer=writer)

    writer = animation.HTMLWriter(fps=4, bitrate=1800, embed_frames=True)
    ani.save(f"{var}.html", writer=writer)

    del ani
  0%|          | 0/2 [00:00<?, ?it/s]
from IPython.display import HTML

HTML("temp.html")
from IPython.display import HTML

HTML("salinity.html")

More forecast T, S#

%autoreload

astral.plot_ts_profiles_line(moors.sel(moor="AD07"))
Hide code cell source
astral.plot_ts_profiles(moors.sel(moor="AD06"))
Hide code cell source
astral.plot_ts_profiles(moors.sel(moor="AD07"))
Hide code cell source
astral.plot_ts_profiles(moors.sel(moor="AD08"))

Development#

preprocessing function#

ds0 = xr.open_dataset(
    "/glade/scratch/acsubram/EKAMSAT/SAC_OSF_CIRC_10KM_20230603.nc",
    decode_times=False,
    chunks={"zt_k": 1, "Time": -1},
)
astral.preprocess(ds0)